/**
 * @file sys_wdt.c
 * @brief 系统软件看门狗（基于硬件看门狗实现）
 * @author wangh (wanghuan3037@fiberhome.com)
 * @version 1.0
 * @date 2021-04-08
 * @copyright Copyright (c) 2021  烽火通信
 */ 
#include "project_config.h"
#define SYS_WDT_EN 1
#define WDT_PERIOD 5
#define WDT_NUM  30
#define SYS_WDT_INTERVAL 1000
#if SYS_WDT_EN
#include "sys_wdt.h"
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include "bsp.h"
#include "bsp_iwdg.h"
#include "bsp_log.h"
#include "app_control.h"
static uint8_t g_threadWdt_num = 0; ///< 任务监测看门狗创建数量
static threadWdt_t *sHead = NULL;   ///< 任务监测看门狗链表头部

threadWdt_t* pp_wdt_arr[ENUM_TASK_UP2 + 1];
uint8_t pp_wdt_len_arr[ENUM_TASK_UP2 + 1] = {
    LONG_ENUM_TASK_LCD          ,         
    LONG_TASK_TILT              ,         
    LONG_TASK_ALARM_SEND        ,        
    LONG_TASK_ALARM_LED         ,       
    LONG_TASK_UART1             ,      
    LONG_TASK_UART5             ,     
    LONG_TASK_BLUETOOTH         ,        
    LONG_TASK_UP1               ,   
    LONG_TASK_STRONG_CURRENT    ,  
    LONG_TASK_WEAK_CURRENT      , 
    LONG_TASK_LEAKAGE           ,
    LONG_TASK_TEMPERATURE       ,
    LONG_TASK_PLAN              ,
    LONG_TASK_HEART             ,
    LONG_TASK_DI                ,
    LONG_TASK_TCP               ,
    LONG_TASK_TCP_RECON         ,
    LONG_TASK_UP2               
};
static void threadWdt_default_cb(void)
{
    app_control_save();
    NVIC_SystemReset();
}

/**
 * @brief 任务监测看门狗创建
 * @param[in]  p_wdt    软狗句柄
 * @param[in]  mvalue   异常最大计数
 * @param[in]  cb       异常回调
 * @return int8_t 0：成功，-1：失败
 */
int8_t threadWdt_Create(threadWdt_t **pp_wdt, uint32_t mvalue, void(*cb)(void),TASK_WDT_MOD task_wdt)
{
    threadWdt_t *pThreadWdt = NULL;
    threadWdt_t *pTmp = sHead;

    if (g_threadWdt_num >= THREADWDT_MAXNUM)
        return -1;

    pThreadWdt = (threadWdt_t *)pvPortMalloc(sizeof(threadWdt_t));
    if (pThreadWdt == NULL)
    {

        return -1;
    }
    pThreadWdt->next = NULL;
    pThreadWdt->Counter = 0;
    pThreadWdt->Enable = 1;
    pThreadWdt->MaxValue = mvalue;
    pThreadWdt->err_cb = (cb == NULL) ? threadWdt_default_cb : cb;
	pThreadWdt->task_wdt = task_wdt;
    if (sHead == NULL)
    {
        sHead = pThreadWdt;
    }
    else
    {
        while (pTmp->next != NULL)
            pTmp = pTmp->next;

        pTmp->next = pThreadWdt;
    }
    *pp_wdt = pThreadWdt;
    g_threadWdt_num++;

    return 0;
}

/**
 * @brief 任务监测看门狗删除
 */
void threadWdt_Delete(threadWdt_t **pp_wdt)
{
    threadWdt_t *pb = sHead;
    threadWdt_t *pf = pb;   /* 记录上个节点 */

    if (sHead ==NULL) return;

    while (pb != *pp_wdt && pb->next != NULL)
    {
        pf = pb;
        pb = pb->next;
    }
    if (pb == *pp_wdt)
    {
        if (pb == sHead)
            sHead = pb->next;
        else
            pf->next = pb->next;

        vPortFree(pb);
        *pp_wdt = NULL;
    }
    g_threadWdt_num--;
}

/**
 * @brief 任务监测看门狗修改
 * @param[in]  p_wdt    软狗句柄
 * @param[in]  enable   使能
 * @param[in]  mvalue   异常最大计数值
 * @param[in]  cb       异常回调
 */
void threadWdt_Control(threadWdt_t *p_wdt, uint8_t enable, uint32_t mvalue, void(*cb)(void))
{
    if (p_wdt == NULL) return;
    p_wdt->Enable = enable;
    if (mvalue != 0) p_wdt->MaxValue = mvalue;
    if (cb != NULL) p_wdt->err_cb = cb;
}


/**
 * @brief 任务监测看门狗喂狗
 */
void threadWdt_Feed(TASK_WDT_MOD task_num)
{
    pp_wdt_arr[task_num]->Counter = 0;
}

///**
// * @brief 任务监测看门狗喂狗
// */
//void threadWdt_Feed(threadWdt_t *p_wdt)
//{
//    p_wdt->Counter = 0;
//}

/**
 * @brief 任务监测看门狗检查
 */
void threadWdt_PollCheck(void)
{
    threadWdt_t *p_Tmp = sHead;

    while (p_Tmp != NULL)
    {
        if (p_Tmp->Enable == 0)
        {
            p_Tmp = p_Tmp->next;
            continue;
        }
        
        p_Tmp->Counter++;
        if (p_Tmp->Counter > p_Tmp->MaxValue)
        {
			log_e("  threadWdt_PollCheck %d \r\n",p_Tmp->task_wdt);
            p_Tmp->err_cb();
        }
		p_Tmp = p_Tmp->next;
    }
}

/**
 * @brief 任务监测线程
 */
void threadWdt_Task(void *para)
{
    iwdg_init(WDT_PERIOD);
    while(1)
    {
        iwdg_feed();
        threadWdt_PollCheck();
        vTaskDelay(SYS_WDT_INTERVAL);
    }
}

/**
 * @brief 软狗初始化
 */
void threadWdt_init( void )
{
    int8_t ret = 0;
    uint8_t i = 0;
    for(i = ENUM_TASK_LCD ; i <= ENUM_TASK_UP2 ; i++)
    {
        ret = threadWdt_Create(&pp_wdt_arr[i],pp_wdt_len_arr[i],NULL,(TASK_WDT_MOD)i);
        if(ret != 0)
        {
            log_e("threadWdt_Create %d FAIL \r\n ",i);
        }
    }
    #if WDT_ENABLE
    if(pdTRUE != xTaskCreate( threadWdt_Task, (const char*)"dog", 256, NULL, 14, NULL))
    {
    }
    #endif
}

#endif  /* SYS_WDT_EN */


/*********** (C) COPYRIGHT 2021 FiberHome *****END OF FILE****/
